package com.uziot.bucket.mdc.util;

import org.slf4j.MDC;
import org.springframework.util.StringUtils;

import java.util.Random;
import java.util.UUID;

/**
 * 功能描述: <br>
 * MD操作方法
 *
 * @author shidt
 * @date 2019-11-07 16:19
 */

public class MdcLogUtil {

    public static final String TRACE_ID = "traceId";
    public static final String SPAN_ID = "spanId";

    public static boolean isTraceUsed;

    private static final String[] CHARS = new String[]{"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z"};

    private static String sequenceNO;
    private static int increment;

    /**
     * 前置方法
     */
    public static void beforeMethod() {
        String traceId = MDC.get(TRACE_ID);
        if (StringUtils.isEmpty(traceId)) {
            traceId = generateTraceId();
            MDC.put(TRACE_ID, traceId);
        }

        String spanId = MDC.get(SPAN_ID);
        if (StringUtils.isEmpty(spanId)) {
            spanId = generateSpanId();
            MDC.put(SPAN_ID, spanId);
        }
    }

    /**
     * 后置方法
     */
    public static void afterMethod() {
        MDC.remove(TRACE_ID);
        MDC.remove(SPAN_ID);
    }

    /**
     * traceId生成规则
     */
    public static synchronized String generateTraceId() {

        return generateUuid(16);
    }

    /**
     * spanId生成规则
     */
    public static String generateSpanId() {
        return generateUuid(8);
    }

    /**
     * 自定义生成UUID方法
     *
     * @param len 生成UUID长度（8、16、32）
     */
    private static String generateUuid(int len) {
        String res;
        switch (len) {
            case 8:
                /*
                 * 算法:
                 * 利用62个可打印字符，通过随机生成32位UUID，由于UUID都为十六进制，所以将UUID分成8组，每4个为一组，然后通过模62操作，结果作为索引取出字符，这样重复率大大降低
                 *
                 * 测试:
                 * 在生成一千万个数据中没有出现重复，完全满足大部分需求
                 */
                StringBuilder stringBuilder = new StringBuilder();
                String uuid = UUID.randomUUID().toString().replace("-", "");
                for (int i = 0; i < 8; i++) {
                    String str = uuid.substring(i * 4, i * 4 + 4);
                    int x = Integer.parseInt(str, 16);
                    stringBuilder.append(CHARS[x % 36]);
                }
                res = stringBuilder.toString();
                break;
            case 16:
                int firstId = new Random().nextInt(10);
                int hashCodeV = UUID.randomUUID().toString().hashCode();
                if (hashCodeV < 0) {
                    // 有可能是负数
                    hashCodeV = -hashCodeV;
                }
                res = firstId + String.format("%015d", hashCodeV);
                break;
            default:
                res = UUID.randomUUID().toString().replace("-", "");
                break;
        }

        return res;
    }

}
